﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;

namespace Pittypat
{
    /// <summary>
    /// 表示一个 16 位有符号整数值。
    /// </summary>
    public struct @int16 : IPrimitive
    {
        /// <summary>
        /// 将指定的字符串解析为一个 int16 值。
        /// </summary>
        /// <param name="s">要解析的字符串。</param>
        /// <param name="provider">提供有关 s 的区域性特定格式信息。</param>
        /// <returns>一个 int16 或 null。</returns>
        public static @int16? Parse(string s, IFormatProvider provider = null)
        {
            if (String.IsNullOrEmpty(s))
            {
                return null;
            }

            s = s.Trim();
            if (String.IsNullOrEmpty(s))
            {
                return null;
            }

            switch (s.ToLower())
            {
                case "min":
                case "minvalue":
                case "min_value":
                    return short.MinValue;
                case "max":
                case "maxvalue":
                case "max_value":
                    return short.MaxValue;
                case "zero":
                case "default":
                    return (short)0;
                default:
                    break;
            }

            short value = 0;
            if (provider != null)
            {
                if (short.TryParse(s, System.Globalization.NumberStyles.None, provider, out value))
                {
                    return value;
                }
            }
            else
            {
                if (short.TryParse(s, out value))
                {
                    return value;
                }
            }

            return null;
        }

        /// <summary>
        /// 比较两个值的大小。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果 x 大于 y，则返回 true，否则返回 false。</returns>
        public static bool operator >(@int16 x, @int16 y)
        {
            return x.value > y.value;
        }

        /// <summary>
        /// 比较两个值的大小。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果 x 大于等于 y，则返回 true，否则返回 false。</returns>
        public static bool operator >=(@int16 x, @int16 y)
        {
            return x.value >= y.value;
        }

        /// <summary>
        /// 比较两个值的大小。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果 x 小于 y，则返回 true，否则返回 false。</returns>
        public static bool operator <(@int16 x, @int16 y)
        {
            return x.value < y.value;
        }

        /// <summary>
        /// 比较两个值的大小。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果 x 小于等于 y，则返回 true，否则返回 false。</returns>
        public static bool operator <=(@int16 x, @int16 y)
        {
            return x.value <= y.value;
        }

        private short value;

        /// <summary>
        /// 初始化 @int16 结构的新实例。
        /// </summary>
        /// <param name="value">结构的值。</param>
        public @int16(short value)
        {
            this.value = value;
        }

        /// <summary>
        /// 将当前值转换为 short 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator short(@int16 value)
        {
            return value.value;
        }

        /// <summary>
        /// 将指定的值转换为 @int16 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator @int16(short value)
        {
            return new @int16(value);
        }

        /// <summary>
        /// 将指定的值转换为 @int16 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator @int16(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return (short)0;
            }

            value = value.ToLower().Trim();
            if (value == "min")
            {
                return short.MinValue;
            }

            if (value == "max")
            {
                return short.MaxValue;
            }

            return new @int16(String.IsNullOrEmpty(value) ? (short)0 : short.Parse(value));
        }

        /// <summary>
        /// 比较两个值是否相等。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public static bool operator==(@int16 x, @int16 y)
        {
            return x.value == y.value;
        }

        /// <summary>
        /// 比较两个值是否不相等。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值不相等，则返回 true，否则返回 false。</returns>
        public static bool operator !=(@int16 x, @int16 y)
        {
            return x.value != y.value;
        }

        /// <summary>
        /// 判断两个值是否相等。
        /// </summary>
        /// <param name="obj">要比较的值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public override bool Equals(object obj)
        {
            if (obj is @int16)
            {
                return this.value == ((@int16)obj).value;
            }

            unchecked
            {
                if (obj is sbyte)
                {
                    return this.value == (sbyte)obj;
                }

                if (obj is byte)
                {
                    return this.value == (byte)obj;
                }

                if (obj is short)
                {
                    return this.value == (short)obj;
                }

                if (obj is ushort)
                {
                    return this.value == (ushort)obj;
                }

                if (obj is int)
                {
                    return this.value == (int)obj;
                }

                if (obj is uint)
                {
                    return this.value == (uint)obj;
                }

                if (obj is long)
                {
                    return this.value == (long)obj;
                }

                if (obj is ulong)
                {
                    return (ulong)this.value == (ulong)obj;
                }

                if (obj is decimal)
                {
                    return this.value == (decimal)obj;
                }

                if (obj is float)
                {
                    return this.value == (float)obj;
                }

                if (obj is double)
                {
                    return this.value == (double)obj;
                }
            }

            return false;
        }

        /// <summary>
        /// 返回此值的哈希代码。
        /// </summary>
        /// <returns>此值的哈希代码。</returns>
        public override int GetHashCode()
        {
            return this.value;
        }

        /// <summary>
        /// 返回此值的字符串表示形式。
        /// </summary>
        /// <returns>此值的字符串表示形式。</returns>
        public override string ToString()
        {
            return this.ToString(null);
        }

        #region IPrimitive Members

        object IPrimitive.Value
        {
            get
            {
                return this.value;
            }
        }

        /// <summary>
        /// 将当前对象作为 JSON 字符串写入指定的文本流。
        /// </summary>
        /// <param name="writer">目标文本流。</param>
        /// <exception cref="ArgumentNullException">writer 是 null。</exception>
        public void Write(System.IO.TextWriter writer)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            writer.Write("{0:G}", this.value);
        }

        #endregion

        #region IConvertible Members

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            return this.value != 0;
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            return unchecked((byte)this.value);
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            return unchecked((char)this.value);
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            return new DateTime(1900, 1, 1).AddMonths(this.value);
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            return unchecked((decimal)this.value);
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            return unchecked((double)this.value);
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            return unchecked((short)this.value);
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            return unchecked((int)this.value);
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            return unchecked((long)this.value);
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            return unchecked((sbyte)this.value);
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            return unchecked((float)this.value);
        }

        string IConvertible.ToString(IFormatProvider provider)
        {
            return this.value.ToString(provider);
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            return ((IConvertible)this.value).ToType(conversionType, provider);
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            return unchecked((ushort)this.value);
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            return unchecked((uint)this.value);
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            return unchecked((ulong)this.value);
        }

        #endregion

        #region IComparable Members

        int IComparable.CompareTo(object other)
        {
            if (other is @int16)
            {
                return this.value.CompareTo(((@int16)other).value);
            }

            return 1;
        }

        #endregion

        #region IFormattable Members

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <param name="formatProvider">用于格式化该值的 IFormatProvider。null 表示从操作系统的当前区域设置中获取数字格式信息。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        public string ToString(string format, IFormatProvider formatProvider)
        {
            return this.value.ToString(format ?? "D", formatProvider);
        }

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        public string ToString(string format)
        {
            return this.ToString(format, null);
        }

        #endregion
    }
}
